Skip to content

Log: a commit covered by the fsync in flight is not refused when the log fails - #2

Merged
marcobambini merged 1 commit into
review-fixesfrom
fix-rollback-race
Oct 11, 2026
Merged

marcobambini merged 1 commit into
review-fixesfrom
fix-rollback-race

Conversation

@marcobambini

Copy link
Copy Markdown
Member

Il problema

mw_rollbackrace falliva in CI (linux-x86_64 build + test, run pull_request di #1, 3 tentativi su 3) con:

after the run: t4 has 80 rows, 79 acknowledged
round 0: 635 rows acknowledged, 4 problems
FAIL test/mw_rollbackrace.c:58: bad == 0

Il fallimento è preesistente: l'ho riprodotto su main (e8acd7e) in un container Linux con 2 CPU pinnate (2 su 150 esecuzioni).

Causa

In sync_staged:

  1. L'append di un commit F fallisce mentre un successore S ha già il suo posto dietro di lui: il log passa in stato failed definitivo.
  2. Un commit W è parcheggiato nella sync e un fsync già in volo sta per renderlo durevole.
  3. W vede failed per primo e restituisce IOERR_FSYNC; poi l'fsync termina, il leader pubblica l'epoch e la riga di W diventa visibile (e presente nel log dopo una riapertura) pur essendo stata dichiarata fallita.

Correzione

Chi trova il log failed aspetta finché c'è un fsync in volo e decide dopo: durevole → confermato, altrimenti rifiutato. Dopo il fallimento non parte nessun altro fsync (tutti i waiter escono), quindi ciò che l'fsync in volo non copre resta invisibile.

8 righe in src/multiwriter_log.c.

Verifica

controllo senza fix con fix
mw_rollbackrace, Linux aarch64, 2 CPU pinnate 2 su 150 (main), 3 su 142 (strumentato) 0 su 700
mw_holesync (nuovo, deterministico) w: commit=10, visible=1 in ogni run passa
make test, make test-mp exit 0
asan: mw_holesync, mw_rollbackrace ok
tsan: mw_holesync ok

mw_holesync forza la sequenza con un fsync bloccato (multiwriter_log.c compilato con -Dfsync=inject_fsync, come mw_stagednormal fa con pwritev): x e w sono coperti dall'fsync tenuto, f fallisce, s è dietro il buco. Senza la correzione w è rifiutato ma visibile.

Da sapere

  • Base review-fixes: il branch contiene anche c663295 e c1cf57e della Fix rebase conflicts, log and ATTACH durability, recovery and row diff OOM #1; il diff di questa PR è solo 57351a1.
  • Non verificato su x86_64: la riproduzione è su aarch64 (container). Che la CI fallisse 3 su 3 mentre io misuro ~2% resta non spiegato; la firma e il meccanismo coincidono.
  • Il test usa stalli temporizzati (MW_FAULT_DELAY_US, 1 s) per ordinare gli eventi, con alarm(30): su un runner molto lento un margine potrebbe stringersi e il sintomo sarebbe un hang visibile.

🤖 Generated with Claude Code

…log fails

The append of one commit failed with a later commit already behind it, so
the log is failed for good. A commit parked in sync_staged whose record the
running fsync was making durable saw `failed` first and returned
IOERR_FSYNC; the leader then finished, published the epoch and the commit
was visible (and in the log after a reopen) although it was told that it had
failed. mw_rollbackrace showed it as "t4 has 80 rows, 79 acknowledged" (2 in
150 runs on two CPUs, also on main; every run on the CI runner of the PR).

A waiter that finds the log failed now waits while an fsync is in flight and
decides after it: durable -> acknowledged, otherwise refused. No fsync begins
once the log is failed, so what the running one does not cover stays
invisible.

mw_holesync reproduces it in every run (x covered by the held fsync, f fails,
s behind the hole): without the change w is refused and visible. The fsync is
held by building multiwriter_log.c with -Dfsync=inject_fsync, as the other
tests do with pwritev and malloc.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@marcobambini
marcobambini merged commit 0c61624 into review-fixes Oct 11, 2026
53 of 54 checks passed
@marcobambini
marcobambini deleted the fix-rollback-race branch October 11, 2026 15:33
@marcobambini marcobambini mentioned this pull request Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant